﻿using EC_6000_Motion_Assistant.SDK;
using lctdevice;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Threading;

namespace NDK.Motion.Card
{
    public enum M60_MOTION_STATUS_ENUM
    {
        //Motion status bit number define.
        //MTS_CSTP = 0,  //Command stop signal.
        //MTS_VM = 1,   // At maximum velocity.
        //MTS_ACC = 2,  //In acceleration.
        //MTS_DEC = 3,  // In deceleration.
        //MTS_DIR = 4,  // LastMoving direction.
        //MTS_NSTP = 5, // Normal stop(Motion done.
        //MTS_HMV = 6,  //In home operation.
        //MTS_SMV = 7,  //Single axis move relative, absolute, velocity move.
        //MTS_LIP = 8,  //Linear interpolation.
        //MTS_CIP = 9,  // Circular interpolation.
        //MTS_VS = 10,  // At start velocity.
        //MTS_PMV = 11,  // Point table move.
        //MTS_PDW = 12,  // Point table dwell move.
        //MTS_PPS = 13,  // Point table pause state.
        //MTS_SLV = 14,  //Slave axis move.
        //MTS_JOG = 15,  //Jog move.
        //MTS_ASTP = 16, // Abnormal stop.
        //MTS_SVONS = 17, // Servo off stopped.
        //MTS_EMGS = 18,  // EMG / SEMG stopped.
        //MTS_ALMS = 19,  // Alarm stop.
        //MTS_WANS = 20,  //Warning stopped.
        //MTS_PELS = 21,  //PEL stopped.
        //MTS_MELS = 22,  //MEL stopped.
        //MTS_ECES = 23,  //Error counter check level reaches and stopped.
        //MTS_SPELS = 24,  // Soft PEL stopped.
        //MTS_SMELS = 25,  //Soft MEL stopped.
        //MTS_STPOA = 26,  // Stop by others axes.
        //MTS_GDCES = 27,  //Gantry deviation error level reaches and stopped.
        //MTS_GTM = 28,    //Gantry mode turn on.
        //MTS_PAPB = 29  // Pulsar mode turn on.
    }
    [Serializable]
    public class LCT_M60 : IMotionCard, IOCard
    {
        private static log4net.ILog traceLogger = log4net.LogManager.GetLogger("LCT_M60");

        #region fileds/properties
        private string _cardName;
        private int _cardID;
        private int _totalAxis;
        private int _inputCount;
        private int _outputCount;
        private string _adlinkCardType;
        private int _startAxisID;
        [NonSerialized]
        private bool _initialized;
        public string CardName
        {
            get
            {
                return _cardName;
            }

            set
            {
                _cardName = value;
            }
        }

        public int CardID
        {
            get
            {
                return _cardID;
            }

            set
            {
                _cardID = value;
            }
        }

        public int TotalAxis
        {
            get
            {
                return _totalAxis;
            }

            set
            {
                _totalAxis = value;
            }
        }

        public int InputCount
        {
            get
            {
                return _inputCount;
            }

            set
            {
                _inputCount = value;
            }
        }

        public int OutputCount
        {
            get
            {
                return _outputCount;
            }

            set
            {
                _outputCount = value;
            }
        }

        public string CardType
        {
            get
            {
                return _adlinkCardType;
            }

            set
            {
                _adlinkCardType = value;
            }
        }

        public int StartAxisID
        {
            get
            {
                return _startAxisID;
            }

            set
            {
                _startAxisID = value;
            }
        }

        public bool Initialized
        {
            get
            {
                return _initialized;
            }

            set
            {
                _initialized = value;
            }
        }


        #endregion

        public bool CardInit(ref List<ICard> motionCards, Int32 mode = 0)
        {
            Int32 ret = 0;
            try
            {
                for (int i = 0; i < 16; i++)
                {
                    try
                    {
                        ecat_motion.M_Close((short)i);
                        Thread.Sleep(100);
                    }
                    catch (Exception e) { }

                    ret = ecat_motion.M_Open((short)i, 0);//第2个参数为预留参数,无效
                    if (ret != 0)
                    {
                        continue;
                    }
                    ret += ecat_motion.M_SetEmgAction(0, (short)i);
                    //设置急停极性 0：常开 1：常闭
                    //ret += ecat_motion.M_SetEmgInv(1, (short)i);
                    ret += ecat_motion.M_SetEmgInv(0, (short)i);
                    ret += ecat_motion.M_ClrEmg((short)i);


                    ret += ecat_motion.M_ResetFpga((short)i);//重置FPGA芯片（针对EtherCAT总线连接超时的问题）
                    ret += ecat_motion.M_LoadEni("C:\\Program Files (x86)\\LCT\\PCIe-M60\\Eni\\eni.xml", (short)i);
                    Thread.Sleep(500);
                    ret += ecat_motion.M_ConnectECAT(1, (short)i);//连接总线，option为设置断线输出保持的参数，0-不保持；1-保持 （注：连接总线需要一定的时间，所需时间会随着从站数量的增多而变长）
                    if (ret == 0)
                    {
                        //获取从站资源
                        ecat_motion.SL_RES Sl_res = new ecat_motion.SL_RES();    //实例ecat_motion.cs接口中用到的“SL_RES 结构体”
                        ret = ecat_motion.M_GetSlaveResource(out Sl_res, (short)i);//获取Ethercat网络中的从站资源
                        if (ret == 0)//如果返回值为0，即获取从站资源成功
                        {
                            LCT_M60 card = new LCT_M60();
                            card.CardID = i;
                            card.CardType = "LCT_M60";
                            card.TotalAxis = (short)Sl_res.AxisNum;//变量 ServoNum 接收 轴数量;
                            card.InputCount = (short)Sl_res.DiNum;
                            card.OutputCount = (short)Sl_res.DoNum;
                            card.StartAxisID = 1;
                            card.Initialized = true;
                            motionCards.Add(card);
                            //加载轴配置文件
                            card.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + i.ToString() + ".ini", card.CardID);
                        }
                    }
                }
                if (motionCards.Count == 0)//没有找到板卡
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("LCT_M60 CardInit Exception:" + ex.StackTrace);
            }
            return true;
        }
        public bool CardInit(Int32 mode = 0)
        {
            Int32 ret = 0;
            try
            {
                {
                    try
                    {
                        ecat_motion.M_Close((short)_cardID);
                        Thread.Sleep(100);
                    }
                    catch (Exception e) { }

                    ret = ecat_motion.M_Open((short)_cardID, 0);//第2个参数为预留参数,无效
                    if (ret != 0)
                    {
                        return false;
                    }
                    ret += ecat_motion.M_SetEmgAction(0, (short)_cardID);
                    //设置急停极性 0：常开 1：常闭
                    //ret += ecat_motion.M_SetEmgInv(1, (short)i);
                    ret += ecat_motion.M_SetEmgInv(0, (short)_cardID);
                    ret += ecat_motion.M_ClrEmg((short)_cardID);


                    ret += ecat_motion.M_ResetFpga((short)_cardID);//重置FPGA芯片（针对EtherCAT总线连接超时的问题）
                    ret += ecat_motion.M_LoadEni("C:\\Program Files (x86)\\LCT\\PCIe-M60\\Eni\\eni.xml", (short)_cardID);
                    Thread.Sleep(500);
                    ret += ecat_motion.M_ConnectECAT(1, (short)_cardID);//连接总线，option为设置断线输出保持的参数，0-不保持；1-保持 （注：连接总线需要一定的时间，所需时间会随着从站数量的增多而变长）
                    if (ret == 0)
                    {
                        //获取从站资源
                        ecat_motion.SL_RES Sl_res = new ecat_motion.SL_RES();    //实例ecat_motion.cs接口中用到的“SL_RES 结构体”
                        ret = ecat_motion.M_GetSlaveResource(out Sl_res, (short)_cardID);//获取Ethercat网络中的从站资源
                        if (ret == 0)//如果返回值为0，即获取从站资源成功
                        {
                            this.Initialized = true;
                            //加载轴配置文件
                            this.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + CardID.ToString() + ".ini", _cardID);
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("LCT_M60 CardInit Exception:" + ex.StackTrace);
            }
            return false;
        }

        public void UpdateSlaveResource(ref ICard motionCard, Int32 mode = 0)
        {
            ecat_motion.SL_RES Sl_res = new ecat_motion.SL_RES();    //实例ecat_motion.cs接口中用到的“SL_RES 结构体”
            var ret = ecat_motion.M_GetSlaveResource(out Sl_res, (short)motionCard.CardID);//获取Ethercat网络中的从站资源
            if (ret == 0)//如果返回值为0，即获取从站资源成功
            {
                motionCard.InputCount = (short)Sl_res.DiNum;
                motionCard.OutputCount = (short)Sl_res.DoNum;
            }
        }
        public bool CheckMoveDone(short axisNum)
        {
            int status = 0;
            // Get motion done bit,normal stop
            ecat_motion.M_GetSts((short)(axisNum), out status, 1, (short)_cardID);

            int isMotionDone = (status & 0x400); // stop                
            if (0 == isMotionDone)//正常停止后
            {
                return true;
            }

            return false;//in motion
        }

        public bool Finalize()
        {
            try
            {
                if (ecat_motion.M_DisconnectECAT((short)_cardID) == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        public bool GetALMStatus(short axisId)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                if (ecat_motion.M_GetSts(axisId, out ServoSts, (short)1, (short)_cardID) == 0)
                {
                    if ((ServoSts & 0x02) == 0x02)
                    {
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetALMStatus Exception! " + ex.StackTrace);
            }

            return false;
        }

        public bool GetASTPStatus(short axisId)
        {
            throw new NotImplementedException();
        }

        public bool GetCmdPosition(short axisId, ref double commandPosition)
        {
            int ret = 0;
            try
            {
                ret = ecat_motion.M_GetCmd(axisId, out commandPosition, 1, (short)_cardID);
                if (ret == 0)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M_GetCmd Exception!" + ex.StackTrace);
            }
            return false;
        }

        public bool GetCSTPStatus(short axisId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// IO模块不是slave号，从1开始重新编号
        /// </summary>
        /// <param name="module"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool GetDI(int module, int port = 0)
        {
            bool ret = false;
            short inputValue = 0;
            try
            {

                if (ecat_motion.M_Get_Slave_Digital_Chn_Input((short)module, (short)port, ref inputValue, (short)_cardID) == 0)//读取成功
                {
                    if (inputValue == 0)
                    {
                        ret = false;
                    }
                    else
                    {
                        ret = true;
                    }
                }
                else//读取失败
                {
                    throw new Exception("M_Get_Digital_Chn_Input Err!");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M_Get_Digital_Chn_Input Exception!" + ex.StackTrace);
            }
            return ret;

        }

        public bool GetDO(int module, int port = 0)
        {
            short outputValue = 0;
            bool ret = false;
            try
            {
                int ret1 = ecat_motion.M_Get_Slave_Digital_Chn_Output((short)module, (short)port, ref outputValue, (short)_cardID);
                if (ret1 == 0)
                {
                    if (outputValue == 0)
                    {
                        ret = false;
                    }
                    else
                    {
                        ret = true;
                    }
                }
                else//读取失败
                {
                    throw new Exception("M_Get_Digital_Chn_Output Err!");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M_Get_Digital_Chn_Output Exception!" + ex.StackTrace);
            }
            return ret;
        }

        public bool GetEMGStatus(short card)
        {
            short emgStatus = 0;
            short ret = 0;
            try
            {
                ret = ecat_motion.M_GetEmg(ref emgStatus, (short)_cardID);//轴卡EMG信号状态: EmgFlag == 1表示急停中（保持信号），EmgFlag == 0 表示急停动作未触发。
                if (ret == 0)
                {
                    if (emgStatus == 1)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    throw new Exception(" M_GetEmg Fail! ret=" + ret);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(" M_GetEmg Exception! " + ex.StackTrace);
            }
        }

        public bool GetErrorPosition(short axisId, ref double errorPosition)
        {
            double cmdPos = 0.0;
            double encPos = 0.0;
            if (GetFeedbackPosition(axisId, ref encPos) == false)
            {
                return false;
            }
            ;
            if (GetCmdPosition(axisId, ref cmdPos) == false)
            {
                return false;
            }
            errorPosition = Math.Abs(cmdPos - encPos);

            return true;
        }

        public bool GetFeedbackPosition(short axisId, ref double feedbackPosition)
        {
            int ret = 0;
            try
            {
                ret = ecat_motion.M_GetEncPos((short)axisId, out feedbackPosition, (short)1, (short)_cardID);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetFeedbackPosition Exception! " + ex.StackTrace);
            }
            return true;
        }

        public bool GetFeedbackVelocity(short axisId, ref double feedbackVelocity)
        {
            int ret = 0;
            try
            {

                ret = ecat_motion.M_GetEncVel((short)axisId, out feedbackVelocity, (short)_totalAxis, (short)_cardID);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetFeedbackVelocity Exception! " + ex.StackTrace);
            }
            return true;
        }

        public bool GetHMVStatus(short axisId)
        {
            short homeStatus = 0;
            short ret = 0;
            try
            {
                int psts = 0;
                homeStatus = 2;//未获取到
                ret = ecat_motion.M_GetSts(axisId, out psts, 1, (short)_cardID);
                if ((psts & 65536) == 65536)
                    homeStatus = -1;//回零错误
                else if (((psts & 131072) == 131072) && ((psts & 262144) == 262144))
                    homeStatus = 3;//回零成功
                else if (((psts & 131072) == 131072) && ((psts & 262144) == 0))
                    homeStatus = 4;//回零中断
                else if (((psts & 131072) == 0))
                    homeStatus = 1;//正在回零
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetHMVStatus Exception! " + ex.StackTrace);
            }
            if (homeStatus == 3)
            {
                return true;
            }
            return false;
        }

        public bool GetINPStatus(short axisId)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                ecat_motion.M_GetSts(axisId, out ServoSts, (short)1, (short)_cardID);
                if ((ServoSts & 0x800) == 0x800)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetAxisMelStatus Exception! " + ex.StackTrace);
            }
            return false;
        }

        public bool GetMELStatus(short axisId)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                ecat_motion.M_GetSts(axisId, out ServoSts, 1, (short)_cardID);
                if ((ServoSts & 0x40) == 0x40)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetAxisMelStatus Exception! " + ex.StackTrace);
            }

            return false;
        }

        public bool GetMotionIoSatus(short axisId, int motionIoStatusBit)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 
        /// 预留 预留 负向极限(MEL) 正向极限(PEL) 预留 预留 预留 伺服报警(ALM) 预留
        /// Bit17 Bit16 Bit15 Bit14 Bit13 Bit12 Bit11 Bit10 Bit9 
        /// 回零完 成 回零错 误 预留 预留 预留 预留 到位(INP) 运动 （MOVE） 使能(SVON)
        /// Bit24 Bit23 Bit22 Bit21 Bit20 Bit19 Bit18
        /// 掉线 (OFFLINE) 预留 预留 预留 原点开 关 预留 目标到达
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="motionStatusBit"></param>
        /// <returns></returns>
        public bool GetMotionStatus(short axisId, int motionStatusBit)
        {
            short ret = 0;
            try
            {
                int ServoSts = 0;
                ret = ecat_motion.M_GetSts((short)axisId, out ServoSts, (short)1, (short)_cardID);
                if ((ServoSts & motionStatusBit) == motionStatusBit)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M_GetSts Exception! " + ex.StackTrace);
            }
            return false;
        }

        public bool GetNSTPStatus(short axisId)
        {
            return !IsMoving(axisId);
        }

        public bool GetORGStatus(short axisId)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                ecat_motion.M_GetSts(axisId, out ServoSts, (short)1, (short)_cardID);
                if ((ServoSts & 0x100000) == 0x100000)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetORGStatus Exception! " + ex.StackTrace);
            }

            return false;
        }

        public bool GetPELStatus(short axisId)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                ecat_motion.M_GetSts(axisId, out ServoSts, 1, (short)_cardID);
                if ((ServoSts & 0x20) == 0x20)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetPELStatus Exception! " + ex.StackTrace);
            }

            return false;
        }

        public bool GetServoOnStatus(short axisId)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                ecat_motion.M_GetSts(axisId, out ServoSts, (short)1, (short)_cardID);
                if ((ServoSts & 0x200) == 0x200)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetServoOnStatus Exception! " + ex.StackTrace);
            }
            return false;
        }

        public bool GetTargetPosition(short axisId, ref double targetPosition)
        {
            int ret = 0;
            int targetPositionPulse = 0;
            try
            {
                ret = ecat_motion.M_GetTargetPos(axisId, ref targetPositionPulse, (short)_cardID);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M60 GetTargetPosition Exception! " + ex.StackTrace);
            }
            return true;
            throw new NotImplementedException();
        }
        public bool HomeMove(
            short axisId,
            PRA_HOME_ENUM homeMode,
            DIR_ENUM homeDir,
            PRA_SF_ENUM homeCure,
            double homeAcc,
            double homeVm,
            double homeVo,
            double homeShiftDistance,
            double stopDec,
            SWITCH_ENUM isEnableSoftLimit,
            double spelPos,
            double smelPos)
        {

            int? ret = 0;
            short HomeStatus = 0;

            //PCIe-M60轴卡的回原方式均为驱动器回原点，以下关于回原点方式的介绍仅供用户参考，具体要依据所使用驱动器的说明书。
            //1： →负极限→EZ（正向）
            //2： →正极限→EZ（负向）
            //17：→负极限
            //18：→正极限
            //23: →正极限→原点
            //27：→负极限→原点
            //33：→负向EZ
            //34：→正向EZ
            //35：当前坐标清零
            short HomeMode = 23;  //回零模式
            if (homeMode == PRA_HOME_ENUM.HOME_MODE_EL)
            {
                if (homeDir == DIR_ENUM.Negative)
                {
                    HomeMode = 17;
                }
                else
                {
                    HomeMode = 18;
                }
            }
            else if (homeMode == PRA_HOME_ENUM.HOME_MODE_ORG)
            {
                if (homeDir == DIR_ENUM.Negative)
                {
                    HomeMode = 27;
                }
                else
                {
                    HomeMode = 23;
                }
            }
            else
            {
                if (homeDir == DIR_ENUM.Negative)
                {
                    HomeMode = 33;
                }
                else
                {
                    HomeMode = 34;
                }
            }

            int HomeOffSet = (int)homeShiftDistance;    //回零偏移
            uint HomeSpeed1 = (uint)homeVm;             //第一回零速度
            uint HomeSpeed2 = (uint)(homeVm / 2);       //第二回零速度
            uint HomeAcc = (uint)homeAcc;               //回零加速度
            ushort ProbeFunction = 0;                   //预留，默认为 0
            try
            {

                ret += ecat_motion.M_SetHomingPrm(axisId, HomeMode, HomeOffSet, HomeSpeed1, HomeSpeed2, HomeAcc, ProbeFunction, (short)_cardID);
                //如果正负软极限的值都给0，表示不启用正负软极限功能
                {
                    ret += ecat_motion.M_SetSoftLimit(axisId, 0, 0, (short)_cardID);
                }
                ret += ecat_motion.M_SetStopDec(axisId, stopDec, stopDec, (short)_cardID);
                ret += ecat_motion.M_Servo_On(axisId, (short)_cardID);
                ret += Ec6000_HomeMove.M60_HomMove(axisId, ref HomeStatus, (short)_cardID);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }



        public bool InterPolationLine(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double vm, double acc = 0.1, double dec = 0.1, PRA_SF_ENUM SF = PRA_SF_ENUM.S_CURVE)
        {
            try
            {

                short axisCount = (short)axisIdArray.Length;
                short[] LineAllAxisArray = new short[axisCount];
                int[] LineAllPosition = new int[axisCount];

                for (int i = 0; i < axisIdArray.Length; i++)
                {
                    LineAllAxisArray[i] = (short)axisIdArray[i];
                }
                for (int i = 0; i < axisIdArray.Length; i++)
                {
                    LineAllPosition[i] = (int)axisPosArray[i];
                }
                short ret = ecat_motion.M_Line_All(axisCount, ref LineAllAxisArray[0], ref LineAllPosition[0], acc, vm, (short)_cardID);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                //m_Logger.Error("多轴直线插补运动失败！" + ex.StackTrace);
                return false;
            }
            return true;
        }

        public bool IsMoving(int axisNum)
        {
            try
            {
                int ServoSts = 0;
                //获取轴状态
                int ret = ecat_motion.M_GetSts((short)axisNum, out ServoSts, (short)1, (short)_cardID);
                if (ret == 0)
                {
                    if ((ServoSts & 0x400) == 0x400)//运动中
                    {
                        return true;
                    }
                }
                else
                {
                    throw new Exception($"GetServoOnStatus Err! RetCode：{ret}");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("GetServoOnStatus Exception! " + ex.StackTrace);
            }
            return false;
        }

        public bool JogMoveStart(short axisId, DIR_ENUM apsOption, double jogVm, double jogAcc)
        {
            int? ret = null;
            try
            {

                if (apsOption == DIR_ENUM.Positive)
                {
                    ret = ecat_motion.M_Jog(axisId, jogVm, (short)_cardID);
                }
                else
                {
                    ret = ecat_motion.M_Jog(axisId, jogVm * -1, (short)_cardID);
                }

                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        public bool JogMoveStop(short axisId)
        {
            int? ret = null;
            try
            {
                ret = ecat_motion.M_StopSingleAxis(axisId, 0, (short)_cardID);//option为停止运动的方式: 0 表示采用平滑减速度停止，1 表示采用急停减速度停止

                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        public bool LoadParamFile(string filePath, int boardId)
        {
            int? ret = null;
            try
            {
                if (File.Exists(filePath))
                {
                    ret = ecat_motion.M_LoadParamFromFile(filePath, (short)boardId);
                    if (ret != 0)
                    {
                        //m_Logger.Error("加载板卡配置文件失败");
                        return false;
                    }
                }
            }
            catch (Exception e)
            {
                traceLogger.Error("加载板卡配置文件失败" + e.Message);
                return false;
            }
            return true;
        }

        public bool MoveVel(short axisId, DIR_ENUM dir, double acc, double dec, double vm, double SF = 0.5)
        {
            int ret = 0;
            ecat_motion.CmdPrm CmdPrm = new ecat_motion.CmdPrm();//实例结构体“CmdPrm”，其中包括 acc 、dec 和 sTime 共3个字段
            try
            {
                // Config speed profile parameters.
                ret += ecat_motion.M_GetMove(axisId, out CmdPrm, (short)_cardID);
                CmdPrm.acc = acc;
                CmdPrm.dec = dec;
                CmdPrm.sTime = 1;
                ret += ecat_motion.M_SetMove(axisId, ref CmdPrm, (short)_cardID);
                if (dir == DIR_ENUM.Positive)
                {
                    ret += ecat_motion.M_Jog(axisId, vm, (short)_cardID);
                }
                else
                {
                    ret += ecat_motion.M_Jog(axisId, vm * -1, (short)_cardID);
                }
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Axis[" + axisId + "] ,Adlink M_Jog Exception!" + ex.StackTrace);
            }
            return true;
        }

        public void P2PMoveWait(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double[] vm, double[] acc, double[] dec)
        {
            int ret = 0;
            for (int i = 0; i < axisIdArray.Length; i++)
            {
                int axisId = axisIdArray[i];

                PTPMove((short)axisId, apsOption, vm[i], acc[i], dec[i], (int)(axisPosArray[i]));
            }



        }

        public void PointTableMove(int _cardId, int axis0, int axis1, double[] x, double[] y, double vm, double acc)
        {
            throw new NotImplementedException();
        }

        public bool PTPMove(short axisId, PRA_OPTION_ENUM ApsOption, double vm, double acc, double dec, double position)
        {
            int ret = 0;
            ecat_motion.CmdPrm CmdPrm = new ecat_motion.CmdPrm();//实例结构体“CmdPrm”，其中包括 acc 、dec 和 sTime 共3个字段
            try
            {
                // Config speed profile parameters.
                ret += ecat_motion.M_GetMove(axisId, out CmdPrm, (short)_cardID);
                CmdPrm.acc = acc;
                CmdPrm.dec = dec;
                CmdPrm.sTime = 1;
                ret += ecat_motion.M_SetMove(axisId, ref CmdPrm, (short)_cardID);
                if (ApsOption == PRA_OPTION_ENUM.Absolute)
                {
                    ret += ecat_motion.M_AbsMove(axisId, (int)position, vm, (short)_cardID);
                }
                else
                {
                    ret += ecat_motion.M_RelMove(axisId, (int)position, vm, (short)_cardID);
                }
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Axis[" + axisId + "] ,Adlink PTPMove Exception!" + ex.StackTrace);
            }
            return true;
        }

        public bool ServoOff(int axisId)
        {
            try
            {
                return (ecat_motion.M_Servo_Off((short)axisId, (short)CardID) == 0);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink ServoOff Exception !" + ex.StackTrace);
            }
        }

        public bool ServoON(int axisId)
        {
            try
            {
                return (ecat_motion.M_Servo_On((short)axisId, (short)CardID) == 0);
            }
            catch (Exception ex)
            {
                throw new Exception("M_Servo_On Exception !" + ex.StackTrace);
            }
        }

        /// <summary>
        /// IO模块不是slave号，从1开始重新编号
        /// </summary>
        /// <param name="module"></param>
        /// <param name="port"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool SetDO(int module, int port, int value)
        {
            try
            {
                short ret = ecat_motion.M_Set_Slave_Digital_Chn_Output((short)module, (short)port, (short)value, (short)_cardID);
                if (ret != 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M_Set_Slave_Digital_Chn_Output Err!" + ex.StackTrace);
            }
        }

        public bool SetPos(int axisId, double pos)
        {
            throw new NotImplementedException();
        }

        public bool StopEmg(short axisId)
        {
            int? ret = 0;

            try
            {
                ret += ecat_motion.M_StopSingleAxis(axisId, 1, (short)_cardID);//option为停止运动的方式: 0 表示采用平滑减速度停止，1 表示采用急停减速度停止

                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StopEmg Exception(axisId:" + axisId + ")! " + ex.StackTrace);
            }
            return true;
        }

        public bool StopMove(short axisId, double acc)
        {
            int? ret = 0;

            try
            {
                ret += ecat_motion.M_StopSingleAxis(axisId, 0, (short)_cardID);//option为停止运动的方式: 0 表示采用平滑减速度停止，1 表示采用急停减速度停止

                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StopMove Exception(axisId:" + axisId + ")! " + ex.StackTrace);
            }
            return true;

        }

        public void TriggleZeroCount(int board, int[] channel, int num)
        {
            throw new NotImplementedException();
        }

        public void TwoDtrigger(int _cardId, int TGR_SRC, int axis0, int axis1, double[] x, double[] y, int windows, int width)
        {
            throw new NotImplementedException();
        }

        public const int ON = 1;
        public const int OFF = 0;





        public bool GetAxisAlarmStatus(short axisId)
        {
            return GetALMStatus(axisId);
        }

        public bool GetAxisMelStatus(short axisId)
        {
            return GetMELStatus(axisId);
        }

        public bool GetAxisPelStatus(short axisId)
        {
            return GetPELStatus(axisId);
        }

        public bool GetEmgStatus(short axisId)
        {
            return GetEMGStatus(axisId);
        }

        /// <summary>
        /// 报警清除
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool ClearAlarm(short axisId)
        {
            int ret = ecat_motion.M_ClrSts((short)axisId, 1, (short)CardID);
            ret += ecat_motion.M_ClrEmg((short)CardID);
            if (ret != 0)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cmpNo">指的是从主站（M60板卡）出发，遇到的第1个LCTE-MINI-CMP模块，从1开始</param>
        /// <param name="mode">设置触发通道的模式（0为通用DO，1为位置比较触发，2为PWM输出）</param>
        /// <param name="triggerOutNumber">每个CMP模块共4个触发输出通道编号（0-3）</param>
        /// <param name="width">脉宽的单位为10ns。</param>
        /// <param name="pulsePolarity"></param>
        /// <param name="encoderNo">每个CMP模块共4个编码器输入编号（0-3）</param>
        /// <param name="preCompareMask">预设定比较器编号（1,2,4,8）对应四个比较器（0001,0010,0100,1000），</param>
        /// <param name="preCompareNo">预设定比较器编号（0-3），</param>
        /// <param name="dir">可以为0、1和2，其中0为正向触发，1为反向触发，2为双向触发</param>
        /// <returns></returns>
        public bool InitialPointTableTrigger(short cmpNo, uint mode, int triggerOutNumber, uint width, int encoderNo, uint preCompareMask, int preCompareNo, int dir)
        {
            try
            {
                //1、将 第1个CMP模块的 输出通道模式 设置为 位置比较触发
                //mode 设置触发通道的模式（0为通用DO，1为位置比较触发，2为PWM输出）            
                Mini_Cmp_Lib.TriggerOut_SetOutMode((short)CardID, cmpNo, mode);

                //2、将 第1个CMP模块的触发输出通道triggerOutNumber 的输出脉宽设置为width*10ns
                //每个CMP模块共4个触发输出通道编号（0-3）
                //注：脉宽的单位为10ns。
                Mini_Cmp_Lib.TriggerOut_SetPulseWidth((short)CardID, cmpNo, triggerOutNumber, width);

                //3、不将 任何比较器 绑定到 触发输出通道 （相当于对触发输出通道triggerOutNumber做了一个重置操作）
                uint LineCompareMask = 0;//线性比较器掩码（这里没有意义）
                uint PreCompareMask = preCompareMask; //预设定比较器掩码
                uint pulsePolarity = 0;  //触发输出通道的输出极性（0为不取反， 1为取反）
                Mini_Cmp_Lib.TriggerOut_SetParam((short)CardID, cmpNo, triggerOutNumber, LineCompareMask, PreCompareMask, pulsePolarity);

                //4、将 预设定比较器PreCompareMask 绑定到 触发输出通道triggerOutNumber
                PreCompareMask = preCompareMask;//“1”对应PreCompareMask参数的 bit0 (0001)位,“2”对应PreCompareMask参数的 bit1 (0010)位,“4”对应PreCompareMask参数的 bit2 (0100)位
                Mini_Cmp_Lib.TriggerOut_SetParam((short)CardID, cmpNo, triggerOutNumber, LineCompareMask, PreCompareMask, pulsePolarity);

                //5、将 编码器输入通道encoderNo 绑定到 预设定比较器preCompareNo
                Mini_Cmp_Lib.PreCmp_BindingEncoder((short)CardID, cmpNo, encoderNo, preCompareNo);

                //6、重置 预设定比较器preCompareNo 的触发数据
                Mini_Cmp_Lib.PreCmp_ResetTrigData((short)CardID, cmpNo, preCompareNo);

                //7、将 预设定比较器preCompareNo 的触发方向设置为正向触发
                Mini_Cmp_Lib.PreCmp_SetTrigDir((short)CardID, cmpNo, preCompareNo, dir);
                //设置编码器输入通道encoderNo,当前的位置0
                Mini_Cmp_Lib.Encoder_SetCurrentData((short)CardID, cmpNo, encoderNo, 0);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        //public bool InitialPointTableTrigger(short cmpNo, uint mode, int triggerOutNumber, uint width, int encoderNo, int preCompareNo, int dir)
        //{
        //    try
        //    {
        //        //1、将 第1个CMP模块的 输出通道模式 设置为 位置比较触发
        //        //mode 设置触发通道的模式（0为通用DO，1为位置比较触发，2为PWM输出）            
        //        Mini_Cmp_Lib.TriggerOut_SetOutMode((short)CardID, cmpNo, mode);

        //        //2、将 第1个CMP模块的触发输出通道triggerOutNumber 的输出脉宽设置为width*10ns
        //        //每个CMP模块共4个触发输出通道编号（0-3）
        //        //注：脉宽的单位为10ns。
        //        Mini_Cmp_Lib.TriggerOut_SetPulseWidth((short)CardID, cmpNo, 0, width);
        //        Mini_Cmp_Lib.TriggerOut_SetPulseWidth((short)CardID, cmpNo, 1, width);

        //        //3、不将 任何比较器 绑定到 触发输出通道 （相当于对触发输出通道0做了一个重置操作）
        //        uint LineCompareMask = 0;//线性比较器掩码
        //        uint PreCompareMask = 0; //预设定比较器掩码
        //        uint pulsePolarity = 0;  //触发输出通道的输出极性（0为不取反， 1为取反）
        //        Mini_Cmp_Lib.TriggerOut_SetParam((short)CardID, cmpNo, 0, LineCompareMask, PreCompareMask, pulsePolarity);
        //        Mini_Cmp_Lib.TriggerOut_SetParam((short)CardID, cmpNo, 1, LineCompareMask, PreCompareMask, pulsePolarity);

        //        //4、将 预设定比较器0 绑定到 触发输出通道0
        //        PreCompareMask = 1;//“1”对应PreCompareMask参数的 bit0 位（0001）
        //        Mini_Cmp_Lib.TriggerOut_SetParam((short)CardID, cmpNo, 0, LineCompareMask, PreCompareMask, pulsePolarity);
        //        PreCompareMask = 2;//“1”对应PreCompareMask参数的 bit1 位（0010）
        //        Mini_Cmp_Lib.TriggerOut_SetParam((short)CardID, cmpNo, 1, LineCompareMask, PreCompareMask, pulsePolarity);

        //        //5、将 编码器输入通道encoderNo 绑定到 预设定比较器preCompareNo
        //        Mini_Cmp_Lib.PreCmp_BindingEncoder((short)CardID, cmpNo, 0, 0);
        //        Mini_Cmp_Lib.PreCmp_BindingEncoder((short)CardID, cmpNo, 1, 1);

        //        //6、重置 预设定比较器preCompareNo 的触发数据
        //        Mini_Cmp_Lib.PreCmp_ResetTrigData((short)CardID, cmpNo, 0);
        //        Mini_Cmp_Lib.PreCmp_ResetTrigData((short)CardID, cmpNo, 1);

        //        //7、将 预设定比较器preCompareNo 的触发方向设置为正向触发
        //        Mini_Cmp_Lib.PreCmp_SetTrigDir((short)CardID, cmpNo, 0, dir);
        //        Mini_Cmp_Lib.PreCmp_SetTrigDir((short)CardID, cmpNo, 1, dir);
        //        //设置编码器输入通道encoderNo,当前的位置0
        //        Mini_Cmp_Lib.Encoder_SetCurrentData((short)CardID, cmpNo, 0, 0);
        //        Mini_Cmp_Lib.Encoder_SetCurrentData((short)CardID, cmpNo, 1, 0);
        //    }
        //    catch (Exception)
        //    {
        //        return false;
        //    }
        //    return true;
        //}
        public bool AddPointTableTriggerPositions(short cmpNo, int preCompareNo, int axisId, List<double> pointTablePositions)
        {
            try
            {
                List<int> list = new List<int>();
                for (int i = 0; i < pointTablePositions.Count; i++)
                {
                    int temp = (int)(pointTablePositions[i]);
                    list.Add(temp);
                }
                //8、向 预设定比较器 内压入点表数据
                Mini_Cmp_Lib.PreCmp_SetTrigData((short)CardID, cmpNo, preCompareNo, list.ToArray());
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="cmpNo">指的是从主站（M60板卡）出发，遇到的第1个LCTE-MINI-CMP模块，从1开始</param>
        /// <param name="preCompareNo">预设定比较器编号（0-3）</param>
        /// <returns></returns>
        public bool TurnOffTrigger(short cmpNo, uint preCompareNo)
        {
            Mini_Cmp_Lib.PreCmp_SetEnable((short)CardID, cmpNo, preCompareNo, 0);//为预设定比较器0下使能（“0”为上使能）
            return true;

        }

        public bool TurnOnTrigger(short cmpNo, uint preCompareNo)
        {
            Mini_Cmp_Lib.TriggerOut_ResetCounter((short)CardID, cmpNo, preCompareNo);
            Mini_Cmp_Lib.PreCmp_SetEnable((short)CardID, cmpNo, preCompareNo, 1);//为预设定比较器0上使能（“1”为上使能）
            return true;

        }
        /// <summary>
        /// 获取触发输出计数
        /// </summary>
        /// <param name="cmpNo"></param>
        /// <param name="triggerOutNumber"></param>
        /// <returns></returns>
        public uint TriggerOut_GetCounter(short cmpNo, int triggerOutNumber)
        {
            uint triggerCounter = 0;
            try
            {
                Mini_Cmp_Lib.TriggerOut_GetCounter((short)CardID, cmpNo, triggerOutNumber, ref triggerCounter);
            }
            catch (Exception)
            {
                return 0;
            }
            return triggerCounter;
        }

        /// <summary>
        /// 手动触发
        /// </summary>
        /// <param name="CmpNo"></param>
        /// <param name="TriggerOutNum"></param>
        /// <returns></returns>
        public int TriggerOut_SetManualOutput(short CmpNo, int TriggerOutNum)
        {
            int ret = 0;
            try
            {
                ret = Mini_Cmp_Lib.TriggerOut_SetManualOutput((short)CardID, CmpNo, TriggerOutNum);
            }
            catch
            {
                return 0;
            }
            return ret;

        }

        public bool InitialPointTableTrigger_2D(short cmpNo, uint mode, int triggerOutNumber, uint width, int encoderNo1, int encoderNo2, int window)
        {
            try
            {
                //1、将 第1个CMP模块的 输出通道模式 设置为 位置比较触发
                //mode 设置触发通道的模式（0为通用DO，1为位置比较触发，2为PWM输出）            
                Mini_Cmp_Lib.TriggerOut_SetOutMode((short)CardID, cmpNo, mode);

                //2、将 第1个CMP模块的触发输出通道0 的输出脉宽设置为1ms
                //每个CMP模块共4个触发输出通道编号（0-3）
                //注：脉宽的单位为10ns。
                Mini_Cmp_Lib.TriggerOut_SetPulseWidth((short)CardID, cmpNo, triggerOutNumber, width);
                //3、将触发输出0绑定2d触发比较器
                Mini_Cmp_Lib.TriggerOut_Set2DCompare((short)CardID, cmpNo, triggerOutNumber, 1);
                Mini_Cmp_Lib._2DCmp_SetCompareSource((short)CardID, cmpNo, (uint)encoderNo1, (uint)encoderNo2);//将2d比较器的X轴source设置为编码器0，Y轴source设置为编码器1
                Mini_Cmp_Lib._2DCmp_SetTrigRegionWindow((short)CardID, cmpNo, 500);//设置触发点的WINDOW区域
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        public bool AddPointTableTriggerPositions_2D(short cmpNo, List<int> axisIds, List<double> xPos, List<double> yPos)
        {
            try
            {
                List<int> xPosList = new List<int>();
                List<int> yPosList = new List<int>();
                for (int i = 0; i < xPos.Count; i++)
                {
                    int xTemp = (int)(xPos[i]);
                    int yTemp = (int)(xPos[i]);
                    xPosList.Add(xTemp);
                    yPosList.Add(yTemp);
                }
                //8、向 预设定比较器 内压入点表数据
                int ret = Mini_Cmp_Lib._2DCmp_SetTrigPoint((short)CardID, cmpNo, xPosList.ToArray(), yPosList.ToArray(), xPosList.Count);//设置2d触发点位
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        [NonSerialized]
        private ecat_motion.CrdCfg crdCfg = new ecat_motion.CrdCfg();//实例CrdCfg结构体（用于设置连续插补参数）
        double[] asv = new double[UInt16.MaxValue * 204];    //速度前瞻运算使用的内存空间

        public bool InitContinueInterpolation(short crd, short fifo, short dimension, List<short> idList, bool isOpenLookAhead)
        {
            crdCfg.dimension = dimension;         //插补维度

            crdCfg.axis = new short[8];   //为了数据对齐，所以该数组的长度为8，用户在使用时只需将参与连续插补的轴号放在crdCfg.axis[]的前4个元素里就行了，后4个元素是无效的         
            for (int i = 0; i < dimension; i++)
            {
                crdCfg.axis[i] = idList[i];           //第一个轴对应的轴号为轴1
            }

            crdCfg.orignPos = new int[8]; //为了数据对齐，所以该数组的长度为8，用户在使用时只需将参与连续插补的轴号放在crdCfg.orignPos[]的前4个元素里就行了，后面4个元素是无效的 
            for (int i = 0; i < dimension; i++)
            {
                crdCfg.orignPos[i] = 0;//起点坐标清零
            }

            crdCfg.evenTime = 10;                                             //最小匀速时间：使每段插补能够强制匀速运动的最小时间，若速度曲线只有加速度段和减速段，可以在尖峰处形成匀速的水平直线，减小速度突变带来的冲击，单位cycletime（默认 1ms）
            crdCfg.synVelMax = 1000000;                                        //坐标系的最大限制插补速度：分段速度大于该速度会默认按该速度运动，单位 pulse/S
            crdCfg.synAccMax = 10000000;                                       //坐标系的最大限制插补加速度：分段加速度大于该加速度会默认按该加速度运动，单位 pulse/S/S                                                                                                      
            crdCfg.synDecSmooth = 10000000;                                    //插补平滑停止减速度：单位 pulse/S/S
            crdCfg.synDecAbrupt = 100000000;                                   //插补紧急停止减速度：单位 pulse/S/S
            short ret = ecat_motion.M_SetCrd(crd, ref crdCfg, (short)CardID);  //设置连续插补运动参数,设定坐标系//坐标系编号:1,2
            ret += ecat_motion.M_CrdClear(crd, 1, fifo, (short)CardID);//设置fifo寄存器：0,1

            //检查是否开启“速度前瞻”功能
            if (isOpenLookAhead == true)
            {
                //ret += ecat_motion.M_SetVelPlanning(crd, fifo, (short)100, crdCfg.synAccMax, 100, ref asv[0], (short)CardID);
            }
            if (ret != 0)
            {
                return false;
            }
            return true;
        }

        public bool AddContinueInterpolationPos_Line(short crd, short fifo, double vel, double acc, List<int> axisIds, List<double> posList)
        {
            //压入pos
            List<int> tepmPosList = new List<int>();
            for (int j = 0; j < crdCfg.dimension; j++)//循环维度
            {
                int temp = (int)(posList[j]);
                tepmPosList.Add(temp);
            }
            int[] posArray = tepmPosList.ToArray();
            short ret = ecat_motion.M_Line(crd, crdCfg.dimension, ref crdCfg.axis[0], ref posArray[0], vel, acc, 0, fifo, (short)CardID);
            if (ret != 0)
            {
                return false;
            }
            return true;
        }
        public bool StartContinueInterpolation(short crd, short fifo)
        {
            short ret = ecat_motion.M_CrdStart(crd, fifo, (short)CardID);//使对应坐标系开始运行连续插补运动  
            if (ret != 0)
            {
                return false;
            }
            return false;
        }
        public bool StopContinueInterpolation(short crd, short fifo)
        {
            short ret = ecat_motion.M_CrdStop(crd, fifo, (short)CardID);//使对应坐标系停止连续插补运动
            if (ret != 0)
            {
                return false;
            }
            return false;
        }


        /// <summary>
        /// 等待连续插补运动完成
        /// </summary>
        /// <param name="crd"></param>
        /// <param name="fifo"></param>
        /// <returns></returns>
        private short sSts = 0;                                      //Buffer状态（1表示运动中，0表示停止状态）
        short sCmdNum = 0;                                   //FIFO里存在的点位数（未到达点位的数量）
        int sSpace = 0;                                      //FIFO剩余空间（sSpace + sCmdNum = 512）
        public bool WaitContinueInterpolationDone(short crd, short fifo)
        {
            int ret = 0;
            do
            {
                Thread.Sleep(10);
                //获取插补状态
                ret = ecat_motion.M_CrdStatus(crd, out sSts, out sCmdNum, out sSpace, fifo, (short)CardID);//获取缓冲区运行状态                    
            }
            while (sSts == 1 || sCmdNum != 0);//判断插补数量为0并且插补状态结束

            //关闭插补功能:连续插补运动完成后，要把连续插补的功能关闭（⬇下面的代码）
            Thread.Sleep(100);
            ret += ecat_motion.M_CrdStop(crd, fifo, (short)CardID);//使对应坐标系停止连续插补运动
            if (ret != 0)
            {
                return false;
            }
            while (true)
            {
                Thread.Sleep(10);
                short psts = 0, pcmdnum = 0; int space = 0;
                ret += ecat_motion.M_CrdStatus(crd, out psts, out pcmdnum, out space, fifo, (short)CardID); //获取缓冲区运行状态
                if (ret != 0)
                {
                    return false;
                }
                if (psts != 1) //插补运动状态( 0：不在运动，1：正在运动 )
                    break;
            }
            return true;
        }

        public bool StartGear(short axisId, GEAR_MODE mode)
        {
            throw new NotImplementedException();
        }

        public bool IsHoming(int axisID)
        {
            //short psts = 0;
            //int ret = 0;
            //try
            //{
            //    ret = Ec6000_HomeMove.M60_HomStsJudgement((short)axisID, out psts, (short)_cardID);
            //    if (ret != 0)//读取状态失败
            //    {
            //        throw new Exception($"M60 IsHoming M_GetSts Err !RetCode{ret}!");
            //    }
            //}
            //catch (Exception ex)
            //{
            //    throw new Exception("M60 IsHoming M_GetSts Exception !" + ex.StackTrace);
            //}

            //if (psts == -1)//回零错误 bit16
            //{
            //    throw new Exception($"M60 Homing Err !");
            //}
            //else if (psts == 3)//回零完成 bit17  && 目标到达  bit18
            //{
            //    return false;
            //}
            //else if (psts == 4)//回零完成 bit17  && 目标未到达  bit18
            //{
            //    return true;
            //}
            //else if (psts == 1)////回零未完成 bit17    正在回零
            //{
            //    return true;
            //}
            //return true;
            try
            {
                int ServoSts = 0;
                //获取轴状态
                int ret = ecat_motion.M_GetSts((short)axisID, out ServoSts, (short)1, (short)_cardID);
                if (ret == 0)
                {
                    if ((ServoSts & 0x10000) != 0x10000)//如果轴没有给出 Homing error 信号
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else
                {
                    throw new Exception($"GetServoOnStatus Err! RetCode：{ret}");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("M60 IsHoming M_GetSts Exception !" + ex.StackTrace);
            }
        }




    }
}
